<?php
class ZData{
	protected $Data  = array();
	protected $cache_files = array(); 
	protected $indexRequest = NULL;
	protected $indexItem = NULL;
	
	//field check
	public function addField( $field, $config=array()){
		if( is_array($field) ){
			return $this->addFields( $field );
		}

		if( !isset($config['request_label']) ){
			$config['request_label'] = $field;
		}
		
		if( !isset($config['form_label']) ){
			$config['form_label'] = $field;
		}
		
		$config['type']	= strtoupper( $config['type'] ); 
		
		$this->Data[$field] = $config;	
	}
	
	public function addFields($arr){
		foreach( $arr as $a => $v )
			$this->addField( $a, $v );	
	}

	public function changeField( $field, $key, $value ){
		if( isset($this->Data[$field])){
			$this->Data[$field][$key] = $value;
		}
	}
	
	public function removeField( $field ){
		if( isset($this->Data[$field])){
			unset($this->Data[$field]);
		}
	}
	
	public function defaultData(){
		$data = array();
		foreach( $this->Data as $field => $config ){
			if( isset($config['default_value']) )
				$data[$field] = $config['default_value'];
		}
		return $data;
	}
	
	public function freeFile(){
		$cache_files = $this->cache_files;
		while( count($cache_files) > 0 ){
			@unlink(array_shift($cache_files));
		}
	}	

	public function setIndexRequest( $index ){
		$this->indexRequest = $index;	
	}

	public function setIndexItem( $index ){
		$this->indexItem = $index;	
	}
	
	public function getData( $hidden_error = false ){
		$data = array();
		$error = NULL;
		if( empty($this->indexRequest) ){
			$REQUEST = $_REQUEST;
			$FILES	 = $_FILES;
		}else{
			$REQUEST = (array)$_REQUEST[$this->indexRequest];
			$FILES 	 = (array)$_FILES[$this->indexRequest];
		}		
		
		foreach( $this->Data as $field => $config ){
			//if field is must set
			$k = isset($config['request_label']) ? $config['request_label'] : $field;
			
			//if field get a static value	
			if( $config['type'] == 'NONE' ){
				$data[$k] = $config['default_value'];
				continue;
			}

				
			$type = strtoupper( $config['type'] );		

			//LIST is a special field 
			if( $type == "LIST" ){
				if( $this->indexItem === NULL  ){
					$rq = (array)$REQUEST[$k];	
				}else{
					$rq = (array)$REQUEST[$k][$this->indexItem];
				}		
				$result = array();	
				$enum_value = (array)$config['value'];
				foreach( $rq as $a ){
					if( in_array( $a, $enum_value ) ){
						$result[] = $a;
					} 
				}
				$data[$field] = implode( isset($config['comma']) ? $config['comma'] : ',', $result);
				continue;	
			}

			//ENUM is a special field 
			if( $type == "ENUM" ){
				if( $this->indexItem === NULL  ){
					$v = $REQUEST[$k];	
				}else{
					$v = $REQUEST[$k][$this->indexItem];
				}	
				$enum_value = (array)$config['value'];
				if( !in_array( $v, $enum_value ) ){
					$error = utf8_ucfirst($config['form_label'])." không được chấp nhận.";
					if(  $hidden_error === false ){
						$this->freeFile();
						return $error;				
					}					
				}
				$data[$field] = $v;
				continue;	
			}			
			
			$is_file 	= in_array( $type, array('FILE','BINARY','IMAGE'));
			$is_files 	= in_array( $type, array('BINARYS','FILES','IMAGES'));			
			
			//when hidden error then not upload
			if( ( $is_file || $is_files ) && $hidden_error ){
				continue;
			}
						
						
			if( $this->indexItem === NULL ){
				if( ( $is_file  && ( !isset($FILES[$k]) || $FILES[$k]['name']=='' ))
					|| ( $is_files && ( !isset($FILES[$k]) || !is_array($FILES[$k]['name']) || $FILES[$k]['name'][0]=='' )) 
					|| ( !$is_file && !$is_files && ( !isset($REQUEST[$k]) || $REQUEST[$k] =='') )
				){
					if( $config['no_empty'] ){
						if( $hidden_error ) continue;
						$this->freeFile();
						return utf8_ucfirst($config['form_label']).' bắt buộc phải nhập.';
					}else{
						if( !$is_file && !$is_files ){
							if( array_key_exists('default_value',$config) ){
								$data[$field] = $config['default_value'];
							}else{
								$data[$field] = isset($REQUEST[$k]) ? $REQUEST[$k] : NULL;
							}	
						}	
						continue;
					}	
				}
			}else{
				if( ( $is_file  && ( !isset($FILES[$k][$this->indexItem]) || $FILES[$k][$this->indexItem]['name']=='' ))
					|| ( $is_files && ( !isset($FILES[$k][$this->indexItem]) || !is_array($FILES[$k][$this->indexItem]['name']) || $FILES[$k][$this->indexItem]['name'][0]=='' )) 
					|| ( !$is_file && !$is_files && empty( $REQUEST[$k][$this->indexItem] ))
				){
					
					if( $config['no_empty'] ){
						if( $hidden_error ) continue;
						$this->freeFile();
						return utf8_ucfirst($config['form_label']).' bắt buộc phải nhập.';
					}else{
						if( array_key_exists('default_value',$config) ){
							$data[$field] = $config['default_value'];
						}else{
							$data[$field] = $REQUEST[$k][$this->indexItem] ? $REQUEST[$k][$this->indexItem] : NULL;
						}
						continue;						
						
					}	
				}else{
					if( !$is_file && !$is_files ){
						$data[$field] = isset($REQUEST[$k][$this->indexItem]) ? $REQUEST[$k][$this->indexItem] : NULL;
					}	
					//continue;
				}
			}	
			
			
			//because when use update and insert
			if( $this->indexItem === NULL  ){
				$value = $REQUEST[$k];	
			}else{				
				$value = $REQUEST[$k][$this->indexItem];
			}	
				
					
			if( isset($config['fix_value']) && function_exists( $config['fix_value'] ) ){				
				$value = $config['fix_value']($value);
			}
			
			if( !is_array( $value ) ){
				$value = stripslashes($value);
			}else{
				foreach( $value as $j => $v ){
					$value[$j] = stripslashes($v);
				}
			}
			
			/* Some config for all field type */
			if( isset( $config['min_length'] ) ){
				if( strlen($value) < (int)$config['min_length'] ){
					$error = utf8_ucfirst($config['form_label'])." quá ngắn ( tối thiểu {$config['min_length']} kí tự )";
				}
			}
				
			if( isset( $config['max_length'] ) ){
				if( strlen($value) > (int)$config['max_length'] ){
					$error = utf8_ucfirst($config['form_label'])." quá dài  ( tối đa {$config['max_length']} kí tự ).";
				}
			}
			
			//check preg_match
			if( isset( $config['mathes'] ) ){
				foreach( $config['mathes']  as $match => $message ){
					if( !preg_match( $match, $value ) ){
						$error = preg_replace( array("{Label}","{label}"), array( utf8_ucfirst($config['form_label']), utf8_lcfirst( $config['form_label'] )), $message);
						break;
					}
				}
			}
	
			if($error == NULL)
				switch( $type ){				
					/* Simple type a non-html string or html string */
					case 'CHAR':
					case 'TEXT':
					case 'HTML':
						$data[$field]= $this->filter( $type != 'HTML' ? escape_html($value) : $value, $config );
						break; 	
						
					case 'EMAIL':
						if( isEmail( $value ) ){ 
							$data[$field]= $this->filter( $value, $config );
						}else{
							$error = utf8_ucfirst($config['form_label'])." không hợp lệ.";
						}	
						break; 	

					case 'DATE':
						if( $value === '' || date('Y-m-d',strtotime( $value )) == $value  ){ 
							$data[$field]= $this->filter( $value, $config );
						}else{
							$error = utf8_ucfirst($config['form_label'])." không hợp lệ.";
						}	
						break; 	

					case 'DATETIME':
						if( $value === '' || date('Y-m-d H:i:s',strtotime( $value )) == $value  ){ 
							$data[$field]= $this->filter( $value, $config );
						}else{
							$error = utf8_ucfirst($config['form_label'])." không hợp lệ.";
						}	
						break; 	
						
					case 'INT':
						if( is_int(intval($value)) ){ 
							//check value in range set
							$num = intval($value);
							if( isset( $config['max'] ) ){
								if( $num > $config['max'] ){
									$error = utf8_ucfirst($config['form_label'])." không được vượt quá {$config['max']}.";
									break;
								}								
							}
								
							if( isset( $config['min'] ) ){
								if( $num < $config['min'] ){
									$error = utf8_ucfirst($config['form_label'])." không thấp hơn {$config['min']}.";
									break;
								}
							}						
						
							$data[$field]= $this->filter( $value, $config );
						}else{
							$error = utf8_ucfirst($config['form_label'])." phải là một số nguyên.";
						}	
						break;
						
					case 'FLOAT':
						if( is_float(floatval($value)) ){ 
							//check value in range set
							$num = intval($value);
							if( isset( $config['max'] ) ){
								if( $num > $config['max'] ){
									$error = utf8_ucfirst($config['form_label'])." không được vượt quá {$config['max']}.";
									break;
								}								
							}
								
							if( isset( $config['min'] ) ){
								if( $num < (int)$config['min'] ){
									$error = utf8_ucfirst($config['form_label'])." không thấp hơn {$config['min']}.";
									break;									
								}
							}								
							$data[$field]= $this->filter( $value, $config );
						}else{
							$error = utf8_ucfirst($config['form_label'])." phải là một số thực.";
						}	
						break;						

					case 'IMAGE':
						$config['file_type'] = array('gif','png','jpg');
					case 'FILE':
						if( $this->indexItem === NULL ){						
							$check = $this->checkFile( $FILES[$k], $config );
						}else{
							$check = $this->checkFile( $FILES[$k][$this->indexItem], $config );
						}	

						if( !is_array($check) ){
							$error = $check;
						}else{							
							$this->cache_files[] = str_replace('//','/',$config['path'].'/'.$check[0] );							
							$data[$field]  = $config['return_name'] ? $check[0] : $check;
						}
						break;
						
					case 'BINARY':
						if( $error !== NULL ) break; 
						$check = $this->checkBinary( $FILES[$k], $config );
						if( !is_array($check) ){
							$error = $check;
						}else{
							$data[$field]= $check[0];
						}
						break;
						
					case 'BINARYS':
						if( $this->indexItem === NULL ){
							$check = $this->checkBinarys( $FILES[$k], $config );
						}else{
							$check = $this->checkBinarys( $FILES[$k][$this->indexItem], $config );
						}
						
						if( !is_array($check) ){
							$error = $check;
						}else{
							$data[$field] = $check;
						}
						break;
						
					case 'IMAGES':
						$config['file_type'] = array('gif','png','jpg');
					case 'FILES':
						if( $this->indexItem === NULL ){						
							$check = $this->checkFiles( $FILES[$k], $config );
						}else{
							$check = $this->checkFiles( $FILES[$k][$this->indexItem], $config );
						}	

						if( !is_array($check) ){
							$error = $check;
						}else{
							foreach( $check as $f ){
								$this->cache_files[] = str_replace('//','/',$config['path'].'/'.$f[0] );
							}
							$data[$field] = $check;
						}
						break;
						
					case 'PASSWORD':
						if( $this->indexItem === NULL ){						
							$value    = $REQUEST[$k];
							$re_pass  = $REQUEST['re_'.$k];
							$old_pass = $REQUEST['old_'.$k];
						}else{
							$value    = $REQUEST[$k][$this->indexItem];
							$re_pass  = $REQUEST['re_'.$k][$this->indexItem];
							$old_pass = $REQUEST['old_'.$k][$this->indexItem];
						}	
						
						if( $value != $re_pass ){ 
							$error = utf8_ucfirst($config['form_label'])." không đồng bộ.";
							
						}else if( isset($config['old_value']) && md5($old_pass) != $config['old_value'] ){
						
							$error = utf8_ucfirst($config['form_label'])." cũ không đúng.";
						}
						
						$data[$field]= $this->filter( md5($value), $config );
						
						break;
					default:
						$error = "Kiểu $type không được chấp nhận.";	
				}
			if(  $hidden_error === false && $error !== NULL ){
				$this->freeFile();
				return $error;				
			}	
		}	

		if( $error === NULL  && count($data)== 0 ){
			$error = "Không có giá trị nào được nhập";
		}
				
		return ( $error === NULL || $hidden_error === TRUE ) ? $data : $error;
	}
	
	
	//we try to upload whether is successful return error or $file_name 
	public function checkFile( $tmp, $config = array()){		
		$config['file'] = $tmp;		
		if( !isset( $config['path'] ) )
			$config['path'] = "files/";
		return upload( $config );
	}
	
	public function checkFiles( $tmp, $config = array()){
		if( !is_array( $tmp['name'] ) ){
			return "File upload lỗi.";
		}
		$all = array();
		$error = "";
		foreach( $tmp['name'] as $i => $k ){
			$pp = array(
				name 		=> $k,
				tmp_name	=> $tmp['tmp_name'][$i],
				size		=> $tmp['size'][$i],
				type		=> $tmp['type'][$i],
				error		=> $tmp['error'][$i],
			);
						
			$config['file'] = $pp;
			if( !isset( $config['path'] ) )
				$config['path'] = "files/";
			$error = upload( $config );
			if( is_array( $error ) ){
				$all[] = $error;
			}
		}
		return ( count($all) == 0 ) ? $error : $all;
	}
	
	public function checkBinary( $tmp, $config = array()){
		if( $config['file_type'] ){
			if( !is_array($config['file_type']) )
				$config['file_type'] = explode(',',$config['file_type']);
			$exts = array();
			$mime = include get_include_path().'/Data/Mime.php';
			$mime = (array) $mime;
			foreach( $config['file_type'] as $k ){
				if( isset( $mime[$k] ) ){
					$exts = array_merge( $exts, $mime[$k] );
				}	
			}
			if( !in_array($tmp['type'],$exts) ){
				return "File ".utf8_lcfirst($config['form_label'])." chỉ chấp nhận định dạng .".implode(',.',$config['file_type']);
			}
		}
		$max_size = (int) $config['max_size'];
		if( $max_size > 0 && $tmp['size'] > $max_size ){
			return "Dung lượng file ".utf8_lcfirst($config['form_label'])." quá lớn.";
		}	

		$f = fopen($tmp['tmp_name'],"rb");
		$data = fread($f,$tmp['size']);
		fclose($f);
	
		return array(array($data,$tmp['type'],$tmp['size'],$tmp['name']));
	}

	public function checkBinarys( $tmp, $config = array()){
		if( !is_array( $tmp['name'] ) ){
			return "File upload lỗi.";
		}
		$all = array();
		$error = NULL;

		//only load mime if set file type	
		if( $config['file_type'] )
			$mime = (array) include get_include_path().'/Data/Mime.php';
		
		foreach( $tmp['name'] as $i => $k ){
			$_tmp = array(
				name 		=> $k,
				tmp_name	=> $tmp['tmp_name'][$i],
				size		=> $tmp['size'][$i],
				type		=> $tmp['type'][$i],
				error		=> $tmp['error'][$i],
			);
						
			if( $config['file_type'] ){
				if( !is_array($config['file_type']) )
					$config['file_type'] = explode(',',$config['file_type']);
				$exts = array();
				foreach( $config['file_type'] as $k ){
					if( isset( $mime[$k] ) ){
						$exts = array_merge( $exts, $mime[$k] );
					}	
				}
				if( !in_array($_tmp['type'],$exts) ){
					$error = "File ".utf8_lcfirst($config['form_label'])." chỉ chấp nhận định dạng .".implode(',.',$config['file_type']);
					continue;					
				}
			}
			$max_size = (int) $config['max_size'];
			if( $max_size > 0 && $_tmp['size'] > $max_size ){
				$error = "Dung lượng file ". utf8_lcfirst( $config['form_label'] )." quá lớn.";
				continue;
			}	

			$f = fopen($_tmp['tmp_name'],"rb");
			$data = fread($f,$_tmp['size']);
			fclose($f);
		
			$all[] = array(array($data,$_tmp['type'],$_tmp['size'],$_tmp['name']));
		}
		return ( count($all) == 0 ) ? $error : $all;
	}
	
	public function filter( $value, $config ){
		if( !isset( $config['filter'] ) || !function_exists( $config['filter'] ))
			return $value;
		$f = $config['filter'];
		return $f( $value );	
	}
}
?>